﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nollie.Storage.Memory;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Nollie.UnitTests.Storage.Memory
{
	[TestClass]
	public class MemoryStorageTests
	{
		private CacheItem GetCacheItem(int customerId, string name)
		{
			var item = new CacheItem();
			item.Key = customerId.ToString();
			item.Value = new Customer(customerId, name);
			item.ExpiryDate = DateTime.Now.AddDays(1);

			return item;
		}

		[TestMethod]
		public void RemoveByTag_should_remove_all_items_with_the_dependency_key()
		{
			var cache = new MemoryStorage(1000000);

			for (int i = 0; i < 100; i++)
			{
				var item = GetCacheItem(i, "Someone" + i.ToString());

				if (i == 50)
					item.Tags.Add("whatever:6");

				cache.Add(item);
			}

			cache.RemoveByTag("whatever:6");

			Assert.AreEqual(99, cache.Count());
		}
		[TestMethod]
		public void Add_should_add_the_item_to_the_end_of_collection()
		{
			var cache = new MemoryStorage(20);

			for (int i = 0; i < 50; i++)
			{
				var item = GetCacheItem(i, "Someone" + i.ToString());

				cache.Add(item);

				var actualItem = cache.GetByIndex(cache.Count() - 1);

				Assert.AreEqual(item, actualItem);
			}
		}
		[TestMethod]
		public void Add_should_remove_the_oldest_item_if_the_collection_is_full()
		{
			// We begin by creating a list of 50 items we want to cache.
			// We then want to add each item to the cache.
			// But before doing it we grab the first item in the cache, and later makes sure that this item
			// is different than the first item in cache after the new item has been added to the cache.

			var capacity = 25;

			var cache = new MemoryStorage(capacity);
			var itemsToCache = new List<CacheItem>();
			
			for (int i = 0; i < 50; i++)
			{
				var item = GetCacheItem(i, "Someone" + i.ToString());

				itemsToCache.Add(item);
			}


			for (int i = 0; i < 50; i++)
			{
				CacheItem firstItem = null;

				if (i >= 25)
					firstItem = cache.GetByIndex(0);

				cache.Add(itemsToCache[i]);

				if (i >= 25)
					Assert.AreNotEqual(firstItem, cache.GetByIndex(0));
			}
		}
		[TestMethod]
		public void Add_should_remove_existing_item_if_key_already_exists()
		{
			var cache = new MemoryStorage(50);

			var item1 = GetCacheItem(1, "Someone1");
			var item2 = GetCacheItem(1, "Someone2");

			cache.Add(item1);
			cache.Add(item2);

			Assert.AreEqual(1, cache.Count());
		}
		public void Get_should_move_the_item_to_the_end_of_collection()
		{

		}
		[TestMethod]
		public void Get_should_return_the_item()
		{
			var item = GetCacheItem(1, "Someone1");

			var cache = new MemoryStorage(10);
			cache.Add(item);

			Assert.AreEqual(item, cache.Get("1"));
		}
		[TestMethod]
		public void Count_reflects_the_number_of_items_in_collection()
		{
			var cache = new MemoryStorage(25);

			for (int i = 0; i < 20; i++)
			{
				var item = new CacheItem();
				item.Key = i.ToString();
				item.Value = new Customer();
				item.ExpiryDate = DateTime.Now.AddDays(1);

				cache.Add(item);

				Assert.AreEqual(cache.Count(), i + 1);
			}
		}
		[TestMethod]
		public void Count_number_of_items_in_collection_should_never_exceed_defined_capacity()
		{
			var capacity = 25;

			var cache = new MemoryStorage(capacity);

			for (int i = 0; i < 75; i++)
			{
				var item = GetCacheItem(i, "Someone" + i.ToString());

				cache.Add(item);

				Assert.IsTrue(cache.Count() <= capacity);
			}
		}
	}
}
